package com.knowledge.business.util;

import com.knowledge.common.utils.StringUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 消息相似度工具类
 * 用于计算两个消息内容的相似度，以实现更智能的热门问题统计
 *
 * @author lingma
 * @date 2025-09-26
 */
public class MessageSimilarityUtil {

    /**
     * 计算两个消息的相似度
     * 使用改进的相似度算法，包括字符级相似度和词级相似度
     *
     * @param message1 消息1
     * @param message2 消息2
     * @return 相似度值，范围0-1，值越大越相似
     */
    public static double calculateSimilarity(String message1, String message2) {
        if (StringUtils.isEmpty(message1) && StringUtils.isEmpty(message2)) {
            return 1.0;
        }
        
        if (StringUtils.isEmpty(message1) || StringUtils.isEmpty(message2)) {
            return 0.0;
        }
        
        // 转换为小写并移除多余空格
        message1 = message1.toLowerCase().trim();
        message2 = message2.toLowerCase().trim();
        
        // 如果完全相等，直接返回1
        if (message1.equals(message2)) {
            return 1.0;
        }
        
        // 计算词级相似度（基于分词）
        double wordSimilarity = calculateWordSimilarity(message1, message2);
        
        // 计算字符级相似度（基于编辑距离）
        double charSimilarity = calculateCharacterSimilarity(message1, message2);
        
        // 加权平均，词级相似度权重0.7，字符级相似度权重0.3
        return 0.7 * wordSimilarity + 0.3 * charSimilarity;
    }
    
    /**
     * 计算词级相似度
     * 使用余弦相似度算法
     *
     * @param message1 消息1
     * @param message2 消息2
     * @return 词级相似度值
     */
    private static double calculateWordSimilarity(String message1, String message2) {
        // 分词并计算余弦相似度
        Set<String> words1 = extractKeywords(message1);
        Set<String> words2 = extractKeywords(message2);
        
        // 计算交集
        Set<String> intersection = new HashSet<>(words1);
        intersection.retainAll(words2);
        
        // 计算并集
        Set<String> union = new HashSet<>(words1);
        union.addAll(words2);
        
        // 余弦相似度 = 交集大小 / 并集大小
        if (union.size() == 0) {
            return 0.0;
        }
        
        return (double) intersection.size() / union.size();
    }
    
    /**
     * 计算字符级相似度
     * 使用编辑距离算法
     *
     * @param message1 消息1
     * @param message2 消息2
     * @return 字符级相似度值
     */
    private static double calculateCharacterSimilarity(String message1, String message2) {
        int len1 = message1.length();
        int len2 = message2.length();
        
        // 创建动态规划表
        int[][] dp = new int[len1 + 1][len2 + 1];
        
        // 初始化边界条件
        for (int i = 0; i <= len1; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= len2; j++) {
            dp[0][j] = j;
        }
        
        // 填充动态规划表
        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                if (message1.charAt(i - 1) == message2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                }
            }
        }
        
        // 计算相似度 = 1 - (编辑距离 / 最大长度)
        int maxLen = Math.max(len1, len2);
        if (maxLen == 0) {
            return 1.0;
        }
        
        return 1.0 - (double) dp[len1][len2] / maxLen;
    }
    
    /**
     * 提取消息中的关键词
     *
     * @param message 消息内容
     * @return 关键词集合
     */
    private static Set<String> extractKeywords(String message) {
        // 简单的关键词提取，按空格分割
        // 实际应用中可以使用更复杂的分词工具，如jieba分词
        String[] words = message.split("[\\s\\p{Punct}]+"); // 按空格和标点符号分割
        return new HashSet<>(Arrays.asList(words));
    }
    
    /**
     * 判断两个消息是否相似
     *
     * @param message1 消息1
     * @param message2 消息2
     * @param threshold 相似度阈值
     * @return 是否相似
     */
    public static boolean isSimilar(String message1, String message2, double threshold) {
        return calculateSimilarity(message1, message2) >= threshold;
    }
}